#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "Errors.h"
#include "Help.h"
#include "Decrypter.h"

#define MD5_LENGTH 32 /* Longitud en bytes de una cadena MD5 */
#define MAX_PWD_LENGTH 6 /* Longitud maxima de los passwords que puede manejar el programa */
#define SALT_LENGTH 2 /* Longitud de la salt */

int main(int argc, char** argv) {

	int next_option;
	int state = 0;
	char* inputFilename = NULL;
	int saltMode = 0;
	int passwordLength = 1; /* Por defecto tiene longitud 1 */
	int paramCounter = 1; /* Puntero de argumentos que recibe el programa */
	FILE *input = NULL;
	unsigned char salt[SALT_LENGTH + 1];
	unsigned char md5FromFileBuffer[MD5_LENGTH + 1]; /*En este buffer guardamos el md5 que leemos del archivo*/

	memset(md5FromFileBuffer, 0, MD5_LENGTH + 1);
	memset(salt, 0, SALT_LENGTH + 1);

	const char* const short_options = "hvls";
	const struct option long_options[] = { { "help", 0, NULL, 'h' }, {
			"version", 0, NULL, 'v' }, { "length", 0, NULL, 'l' }, { "saltMode",
			0, NULL, 'l' }, { NULL, 0, NULL, 0 } };

	do {
		next_option = getopt_long(argc, argv, short_options, long_options,
				NULL);
		switch (next_option) {
		case 'h':
			printHelp(argv[0]);
			exit(0);
		case 'v':
			printVersion();
			exit(0);
		case 'l':
			paramCounter++;
			passwordLength = atoi(argv[paramCounter]);
			break;
		case 's':
			paramCounter++;
			saltMode = 1;
			break;
		case '?':
			exit(1);

		default:
			break;
		}

	} while (next_option != -1);

	if ((paramCounter + 1) >= argc - 1) {

		inputFilename = argv[(paramCounter + 1)];
		input = fopen(inputFilename, "r");
		if (input == NULL) {
			/* No se pudo abrir el archivo de entrada */
			open_file_error(inputFilename);
			state = ERROR_APERTURA_ARCHIVO;
		} else {
			int firstIteration = 1;
			/* Se lee el md5 del archivo */
			while (!feof(input)) {
				unsigned char password[MAX_PWD_LENGTH + 1]; /*Si se pudo desencriptar aca va el resultado*/
				memset(password, 0, MAX_PWD_LENGTH + 1);
				if (fgets((char*) md5FromFileBuffer, MD5_LENGTH + 1,
						input) == NULL) {
					if (!feof(input)) {
						read_file_error(inputFilename);
						state = ERROR_LECTURA_ARCHIVO;
					}
					break;
				} else {
					fgetc(input);
					if (firstIteration == 1 && saltMode == 1) {
						/* Hago primera iteracion para obtener la salt */
						bruteForce(md5FromFileBuffer, passwordLength, NULL, 0,
								password);
						printf("%s\n", password);
						int i;
						for (i = 0; i < SALT_LENGTH; i++) {
							salt[i] =
									password[passwordLength - SALT_LENGTH + i]; /* Copio la salt */
						}
						firstIteration = 0;
					} else {
						if (bruteForce(md5FromFileBuffer, passwordLength, salt,
								saltMode, password) == 1) {
							/* Se logro desencriptar */
							printf("%s\n", password);
							firstIteration = 0;
						} else {
							printf("No se logro desencriptar el md5: %s\n",
									md5FromFileBuffer);
						}
					}

				}
			}

			if (fclose(input) < 0) {
				close_file_error(inputFilename);
				state = ERROR_CIERRE_ARCHIVO;
			}
		}

	}
	return state;
}
